import Vue from 'vue'
import VueRouter from 'vue-router'
import { cancel } from '@/api/conn'
import utils, { bus } from '@/utils/utils'
import { store } from '../store/base'
import { config } from '@/utils/config'
import MainLayout from '@/views/main/MainLayout.vue'

Vue.use(VueRouter)
const routes = [
  {
    path: '*',
    component: MainLayout
  }
]

export let router
// 外部传入的路由配置
let otherRoutes = []

export function init ({ routes: children, mode = 'history' }) {
  // 增加登录页面的路由
  routes.unshift({
    path: '/login',
    // FIX 注册的组件在这里发现会比router后加载，导致组件找不到
    component: Vue.component('os-login') || (() => import('../views/main/Login.vue'))
  })
  otherRoutes = children
  router = new VueRouter({
    base: process.env.BASE_URL || '/',
    mode: mode,
    routes
    // routes: children // 测试开发使用，不加登录
  })
  router.beforeEach((to, from, next) => {
    // 取消未完成的网络请求
    cancel()
    // 控制一些页面不能直接访问
    if (from.path === '/' && to.meta && to.meta.redirect) {
      next(to.meta.redirect)
    }
    const title = (to.meta && to.meta.title) || ''
    if (title) {
      document.title = title
    }
    next()
  })
  return router
}

export const tabUtils = {
  add (path, name, replace) {
    const menuTabs = store.state.menuTabs
    const activeTab = store.state.activeTab // 当前激活的tabId
    const menu = this.getMenu(path, name)
    // console.log('menu: ' + JSON.stringify(menu))
    const tabId = menu.id
    // 判断是不是子应用,子应用通过activeRule匹配tab
    const app = this.getChildApp(path)
    // 先查询有没有打开的标签，app在main.js定义，为外部子应用系统
    // let tab = menuTabs.find(mt => mt.id === (tabId || app) && app.name === mt.appName)
    let tab = menuTabs.find(mt => mt.id === tabId)
    console.log('查找tab', tab)
    // 如果没有tab，则构建
    if (!tab) {
      // 根据path获取组件
      const route = otherRoutes.find(r => r.path === menu.path.replace(/^(.*)\?.*/, '$1')) // 菜单的path和路由的path一定是没有参数的，不然不能匹配
      if (route) {
        tab = {
          id: tabId,
          title: name || menu.name,
          path,
          component: route.component
        }
        // 处理路由参数
        this.setRoute(tab)
        if (replace) {
          store.commit('replaceTab', { oldId: tab.id, tab })
        } else {
          store.commit('addTab', tab)
        }
      } else {
        // 创建子应用的tab
        if (app) {
          tab = {
            id: tabId,
            title: name || menu.name,
            path,
            appName: app.name,
            container: app.container.replace('#', '')
          }
          // console.log('子应用Tab添加')
          store.commit('addTab', tab)
        } else {
          // console.log('路由不存在')
          return
        }
      }
    } else {
      // 如果存在已经打开的tab，需要处理参数改变的情况
      const newTab = { ...tab, path, id: menu.id, title: menu.name || tab.title }
      this.setRoute(newTab)
      store.commit('replaceTab', { oldId: tab.id, tab: newTab })
    }
    // 切换到tab
    if (tab.id !== activeTab) {
      this.select(tab.id)
    }
  },
  replace (path, name) {
    this.add(path, name, true)
  },
  change (id, curPath) {
    this.select(id)
    const menuTabs = store.state.menuTabs
    const tab = menuTabs.find(mt => mt.id === id)
    if (tab) {
      if (tab.path !== curPath) {
        router.push(tab.path)
      }
    }
  },
  select (id) {
    store.commit('update', { activeTab: id })
  },
  getComponent (path) {
    // 去除query的path
    const shortPath = path.replace(/^(.*)\?.*/, '$1')
    const route = this.matchRoute(shortPath)
    if (route) {
      return route.component
    }
  },
  closeById (id) {
    store.commit('closeTab', id)
  },
  // 关闭tab，并跳转到新tab
  close (toPath, refresh) {
    this.closeById(store.state.activeTab)
    if (toPath) {
      const menuTabs = store.state.menuTabs
      const tab = menuTabs.find(mt => mt.path === toPath)
      if (tab) {
        this.select(tab.id)
        if (refresh) {
          setTimeout(() => (this.refresh(toPath)))
        }
      }
    }
  },
  // 通过path获取匹配到的菜单
  getMenu (path, name, newTab) {
    // 去除query的path
    const shortPath = path.replace(/^(.*)\?.*/, '$1')
    let menu = null
    if (path === '/') {
      menu = { id: '0', path, name: '首页' }
    } else {
      const flatMenu = store.getters.flatMenu // 全部菜单
      // 先找完全相等的
      menu = flatMenu.find(m => m.path === shortPath)
      // 找不到再找开头匹配的   这种匹配会有一些问题，所以暂时注释，不要在菜单里面配置参数
      // menu = menu || flatMenu.find(m => m.path !== '/' && path.startsWith(m.path))
      if (menu) {
        return menu
      } else {
        // 如果没有path匹配不到合适的菜单，就生成一个菜单
        const route = this.matchRoute(shortPath)
        let newTab = utils.url2Obj(path).newTab
        if (newTab === undefined) newTab = config.forceMultiTab
        const menuPath = newTab ? path : route ? route.path : null
        name = name || route?.meta?.title
        menu = { id: utils.hashCode(menuPath), name, path: menuPath }
      }
    }
    return menu
  },
  // 刷新tab
  refresh (path) {
    bus.$emit('refresh-tab', path)
  },
  matchRoute (path) {
    // const route = otherRoutes.find(r => r.path.replace(/^(.*?)\/[(:].*/, '$1') === path)
    const route = otherRoutes.find(r => {
      // 直接相等的情况
      if (r.path === path) {
        return true
      } else {
        // 存在params的情况
        const ps1 = r.path.split('/')
        const ps2 = path.split('/')
        if (ps1.length === ps2.length) {
          return ps1.every((p, index) => p.startsWith(':') || p.startsWith('(') || p === ps2[index])
        }
      }
    })
    return route
  },
  getChildApp (path) {
    if (Array.isArray(config.apps)) {
      return config.apps.find(item => path.startsWith(item.activeRule.replace('/#', '')))
    }
  },
  setRoute (tab) {
    tab.query = utils.url2Obj(tab.path)
    // params
    const shortPath = tab.path.replace(/^(.*)\?.*/, '$1')
    const ps1 = shortPath.split('/')
    const ps2 = tab.path.split('/')
    const params = {}
    if (ps1.length === ps2.length) {
      ps2.forEach((p, index) => {
        if (p.startsWith(':')) {
          params[p.replace(':', '')] = ps1[index]
        }
      })
    }
    tab.params = params
  }
}
